teratail header banner
teratail header banner
質問するログイン新規登録

質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.30%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

2回答

784閲覧

__setattr__で、クラス外からの設定とクラス内からの設定を区別する方法はないでしょうか?

DATA

総合スコア1

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

0クリップ

投稿2022/10/24 10:09

0

0

実現したいこと

お世話になっております。

Pythonのクラスでなんとかprivateなインスタンス変数が作れないかと思っています。__は、クラス名をつけると変更できてしまうので ... orz、

最初は、__setattr__でインスタンス変数への設定がcatchできると聞いて、ここでインスタンス変数の変更をチェックすれば、privateなインスタンス変数が作れるかと思っていたら、__setattr__は、クラス外からの設定もクラス内からの設定もcatchしてしまうようですT^T)/。

例えば、以下で、(__setattr__に限らず)(1)(2)と(3)を区別したいのですができないものでしょうか?

class SampleSetattr(): def __init__(self): self.x = 1 # (1) def __setattr__(self, name, value): print('__setattr__メソッドが呼び出されました', name, value) def set(self, a): self.x = a # (2) data = SampleSetattr() data.x = 2 # (3) data.set(3)

Pythonでは、どうやっても無理なのですかね ...
よろしくお願いします

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

TakaiY

2022/10/24 11:38

「なんとかprivateなインスタンス変数が作れないか」 基本そういう機能の無いpython言語をつかってprivateの変数を作りたい理由って何でしょう?
guest

回答2

0

PEP8より引用

ここでは "private" という用語を使っていません。なぜなら、Python の世界で本当の意味で private なものは存在しない (実現するには通常は不要なほどの多くの作業が必要です) からです。

おすすめする訳ではありませんが、技術的な挑戦であれば
実行時のフレーム情報で呼び出し元のスコープを判別することは可能です。
(inspect モジュール等)

但し、実行時チェックなので、静的コード解析において何の役にも立たない、という欠点があります。
多くの場合は private や protected はコード検査において有用なはずなので。

もしデータの完全な隠蔽を望まれてるのでしたら、その観点からは何の役にも立ちません。

抜け穴として、動的に外部から既存クラスへメソッドを追加する方法もあります。
これは、private ならクラス内のメソッドからはアクセス可能になるべきですが、
そもそも外部からメソッドを動的に追加できてしまうので、判別がつかなくなります。

結論としては、(段階にもよりますが) どうやっても無理なので
そのような機能が必要になるケースでは、必要としてる機能自体を見直したほうが良い場合が殆どです。

PEP8 のガイドラインを読んで、既存の慣習・機能ではどうしても代用できないかを熟考しましょう。
現実的には、作業量に見合う効果があるのか、妥協ができない事項なのか、等も検討材料になるはず。

ちなみに、他の private が実装されている言語でも、
リフレクション等の機構を通じて外部から private な変数へアクセスする手段はあります。
Python では比較的容易にできてしまう程度の違いでしかありません。

投稿2022/10/24 11:04

teamikl

総合スコア8817

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

teamikl

2022/10/24 11:17 編集

静的・動的にチェックする場合のメリット・デメリットを明確にしておくと アンダーバーによる慣習では、静的コード解析により事前に検出可能ですが、 実行時のフレームを用いた動的な判別は、テストを作って実際に実行するまで検出できません。
DATA

2022/10/25 09:17

ありがとうございます。 >PEP8 のガイドラインを読んで、既存の慣習・機能ではどうしても代用できないかを熟考しましょう。 >現実的には、作業量に見合う効果があるのか、妥協ができない事項なのか、等も検討材料になるはず いえいえ、 >おすすめする訳ではありませんが、技術的な挑戦であれば こちらです もう少し質問を丁寧にかけば、ご苦労を減らせたのではないかとちょっと反省しています。
teamikl

2022/10/25 10:02

恐らく伝わってない箇所がありそうなので、そこだけ強調しておくと > なんとかprivateなインスタンス変数が作れないかと思っています。 > __は、クラス名をつけると変更できてしまうので とのことなので、目的が「privateなインスタンス変数」の場合は、 呼び出し元の判別しても、他にも外部から変更できてしまう手段があるという点の指摘です。 質問の題名に対する回答としては、inspect モジュールを使う方法で良いと思います。 私の回答は「privateな変数」に対する質問の方法自体の否定になってしまっているので、 回答としては不適切だったかなと思うところはあります。
DATA

2022/10/30 09:52

ありがとうございます。 > 呼び出し元の判別しても、他にも外部から変更できてしまう手段があるという点の指摘です。 それはそれで理解できたので勉強になりました > 私の回答は「privateな変数」に対する質問の方法自体の否定になってしまっているので、 > 回答としては不適切だったかなと思うところはあります。 いえいえ、それはそれで勉強になったという意味では広義の意味で適切だと思います。 重ねてお礼申し上げます。Best Answerって2つ付けられないのですかね ... ^-^;)/
guest

0

ベストアンサー

例えば、以下で、(__setattr__に限らず)(1)(2)と(3)を区別したいのですが

inspect モジュールを利用する場合。

python

1import inspect 2 3class SampleSetattr(): 4 def __init__(self): 5 self.x = 1 # (1) 6 def __setattr__(self, name, value): 7 print('caller name:', inspect.stack()[1][3]) 8 print('__setattr__メソッドが呼び出されました', name, value) 9 def set(self, a): 10 self.x = a # (2) 11 12data = SampleSetattr() 13data.x = 2 # (3) 14data.set(3) 15 16# 17caller name: __init__ 18__setattr__メソッドが呼び出されました x 1 19caller name: <module> # ※ main module から 20__setattr__メソッドが呼び出されました x 2 21caller name: set 22__setattr__メソッドが呼び出されました x 3

投稿2022/10/24 10:52

melian

総合スコア21259

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

DATA

2022/10/25 09:18

ありがとうございます。 なるほどなかなかなモジュールが存在するのですね。 勉強になります(しかしその名も、 inspect.stackですか... ^-^;)/)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.30%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問