iT邦幫忙

0

我希望B於A底下,並且B繼承A的所有東西

  • 分享至 

  • xImage
class A:
    class B(A):
        pass
#//////////////////////////////////////
Traceback (most recent call last):
  File ".\test.py", line 1, in <module>
    class A:
  File ".\test.py", line 2, in A
    class B(A):
            ^
NameError: name 'A' is not defined

如果是類似super的方法我應該沒辦法用
因為我其實要用的地方是

class Config:
    class default:
        class language:
            #code
    class first_online:
        class language(Config.default.language):
            #code

大概是這種感覺
這是有辦法的嗎?
或是直接就是不可能?

看更多先前的討論...收起先前的討論...
SunM0on iT邦新手 4 級 ‧ 2024-08-01 17:28:40 檢舉
看得我頭皮發麻,建議你直接說妳想實現什麼樣的效果,從你的code看不太懂你想做的事是甚麼,而且你的code好可怕
不太懂可怕的點,是重複的原因嗎?

然後我希望可以實現像是這樣的效果
比如肚子餓就把麵包全部吃掉
____________________________________________________________
..............................................................................__ 牛角麵包
......................................................___ 麵包類--||_ 波羅麵包
......................................................||
....................___ 袋子裡有的 - ||.......................__ 蘋果牛奶
.一個袋子||........(default)......||__ 牛奶類--||_ 木瓜牛奶
.(Config)...||
....................||__ 肚子餓了想吃 -- 袋子裡的麵包
....................||.........(first_online).....(Config.default.麵包類)
................... ||__ 嘴巴渴了想喝 -- 袋子裡的牛奶
...............................................................(Config.default.牛奶類)

--------------------------------------------------------------------
更詳細在底下回答那邊
這裡好像不能用空格去讓他看起來整潔
所以多少會傷點眼睛就不好意思了
froce iT邦大師 1 級 ‧ 2024-08-02 08:22:41 檢舉
&gt; 不太懂可怕的點,是重複的原因嗎?

1. 你根本沒搞懂作用域在在幹嘛...連錯誤log都跟你說了你還是看不懂
2. 就算作用域讓你過,你這還會涉及到無限繼承樹,你自己想一下,你這樣寫,A在實例化的時候會做些什麼?A實例化,B繼承A,B裡面會仿造A再實例化,B裡面會不會又再生出一個C也繼承A,C裡面又再生一個D也繼承A....
3. 要簡潔就直接一個Config裡面把default值寫進去就好
Kailis iT邦研究生 1 級 ‧ 2024-08-02 09:54:52 檢舉
AI 回覆供參

這段程式碼中定義了一個類別A,然後在A內部又定義了一個類別B,並且讓B繼承自A。然而,這段程式碼出現了錯誤,錯誤訊息顯示在定義B的地方找不到名為A的定義。這是因為在Python中,當我們在類別內部定義另一個類別時,需要使用完整的類別名稱,而不是只使用類別名稱本身。因此,應該將class B(A)改為class B(A.A)。這樣就可以正確地定義B並讓其繼承自A。
froce iT邦大師 1 級 ‧ 2024-08-02 10:03:58 檢舉
to Kailis:
AI會唬爛,不信你自己寫範例試試看。
對AI唬爛我
底下就是AI跟我說的
也正是如此所以我才跑來IT問大家XD
class A:
....class B(A):
........pass
名詞說甚麼叫內部繼承
網上完全查無
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

2 個回答

1
meebox
iT邦新手 3 級 ‧ 2024-08-02 09:27:35
最佳解答

先不管你想做什麼, 純粹語法上來說, 錯誤訊息已經告訴你不可行:

>>> class A:
...     class B(A):
...         pass
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in A
NameError: name 'A' is not defined

因為定義 B 的時候, A 還沒有完整定義, 所以錯誤訊息告訴你 A 尚未定義。

看更多先前的回應...收起先前的回應...

謝謝原來是這樣!!
那我知道了不行的原因了

不過這樣我就有新的疑問(這人問題好多XD)

class A:
    class B1:
        pass
    class B2:
        class C(B1):#or class C(A.B1):
            pass

這樣的狀況A底下的B1不是已經被完整定義了嗎?
怎麼還是不行?

froce iT邦大師 1 級 ‧ 2024-08-02 11:09:54 檢舉

一樣作用域的問題。你這樣寫和你原本寫的不是一樣嗎?就往下移一層而已。

雖然不知道為甚麼
不過好像是不行的
圖片

meebox iT邦新手 3 級 ‧ 2024-08-04 14:03:46 檢舉

因為 B1 是 A 的屬性, 所以你要寫 A.B1 才能存取到 B1 的定義, 單獨寫 B1 就會是沒有定義的名稱, 所以會說 B1 未定義。這可以透過底下的例子說明:

>>> class A:
...     class B1:
...         pass
...     def foo(self):
...         print(B1)
...     def foo1(self):
...         print(A.B1)
>>> a1 = A()
>>> a1.foo()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in foo
NameError: name 'B1' is not defined

>>> a1.foo1()
<class '__main__.A.B1'>

但如果要在 A 的定義內使用 A.B1, 就遇到同樣的問題了, 在定義 C2 的這一行時, A 還是沒有定義完成, 所以它會說 A 未定義。

如果你是在 A 中的函式定義新類別, 那就沒問題了, 例如:

>>> class A:
...     class B1:
...         pass
...     def foo(self):
...         class C1(A.B1):
...             pass
...         return C1()
>>> a1 = A()
>>> c1 = a1.foo()
>>> type(c1)
<class '__main__.A.foo.<locals>.C1'>

雖然定義 C1 的程式碼也是寫在 A 內, 但是實際定義的動作是發生在 foo 執行時, 而這一定是 A 已經定義完成後才會生的事。

非常感謝你的回覆
我還以為真的沒有任何方法已經算是放棄了

之前別人回復我是以A當作藍圖做舉例
其實我一直有疑問為甚麼不能在圖紙之中分割一個小區域
用作描述其他部分會使用到的公用部件,如B1
也就是藍圖內又有小藍圖XD
目前看起來是因為我少了一個定義的動作
類比的話就好像我沒有在藍圖內劃定範圍
這樣就導致閱讀的人(電腦)以為是一個整體

你說的方法我回頭會再試試,謝謝你的幫助
現在我又學到了一課,謝謝你

froce iT邦大師 1 級 ‧ 2024-08-07 16:49:54 檢舉

其實我一直有疑問為甚麼不能在圖紙之中分割一個小區域
用作描述其他部分會使用到的公用部件,如B1

誰說不可以,可以啊,問題是部件和本體不會相同,你吹風機裡面電熱絲會和吹風機一樣一個類嗎?哪怎麼會用到繼承?

我一直在跟你說class in class會用到的大部分是封裝,但你想要用的用法是繼承,這就很有問題了。

另外藍圖通常會都畫完,放在那邊,要生產的時候再取用(實例化)。實例化的時候才會比較有判斷是去操作。
不太會有哪種需要判斷哪種藍圖什麼時候開始畫的狀況。

來,這是linebot的message的類,你自己看看人家code怎麼寫的,和你的差多少?人家的一樣用到繼承有和你一樣一層一層class嗎?
https://github.com/line/line-bot-sdk-python/blob/master/linebot/models/messages.py

然後一直跟你說,直接把config的格式完整寫一個範例,就會有人幫你生個code了...

1
froce
iT邦大師 1 級 ‧ 2024-08-01 11:28:23

class 不是這樣玩的...說真的看不懂你為何要這樣設計。

class ConfigSetting:
    ...

class Config:
    def __init__(self, default:ConfigSetting, settings:ConfigSetting ):
        self.default = default
        self.settings =settings
        
default = ConfigSetting(....)
settings = ConfigSetting(....)
config = Config(default=default, settings=settings)
# 照你的格式去寫的,雖然我對你Config裡面還要塞莫名其妙的同類東西感到不解,命名也很奇怪。

這樣不是很好嗎?
在class裡面寫class通常是為了封裝,不是為了繼承。
如果你是要做類似節點這種樹狀結構的話,也用不到繼承。

看更多先前的回應...收起先前的回應...

default是打算放在那邊
當我其他地方有用到的時候就從那裏叫出

比如我需要用到language底下的東西時
我希望直接class language(default.language):就好
如果有需要添加或修改後續再添加或修改

然後因為我是打算用Config直接封裝全部所以這樣寫
大概邏輯是

                                        __ 牛角麵包
                            ___ 麵包類--|__ 波羅麵包
           ___ 袋子裡有的 - |            __ 蘋果牛奶
一個袋子 - |   (default)    |___ 牛奶類--|__ 木瓜牛奶
(Config)  |
          |___  肚子餓了想吃 --  袋子裡的麵包
          |   (first_online)   (Config.default.麵包類)
          |___  嘴巴渴了想喝 --  袋子裡的牛奶
                               (Config.default.牛奶類)

當然我也可以兩個袋子
一個專門裝已經有的
一個裝之後的會觸發的事件
而且事實上我目前就是這麼做

                         __ 牛角麵包
             ___ 麵包類--|__ 波羅麵包
袋子裡有的 - |            __ 蘋果牛奶
(default)   |___ 牛奶類--|__ 木瓜牛奶
-----------------------------------------------
           ___  肚子餓了想吃 --  袋子裡的麵包
一個袋子 - |   (first_online)   (default.麵包類)
(Config)  |___  嘴巴渴了想喝 --  袋子裡的牛奶
                               (default.牛奶類)

但說實話我還是想整個收在Config裡
比較乾淨XD

froce iT邦大師 1 級 ‧ 2024-08-02 08:07:31 檢舉

你把default直接定在class內就好,某個物件專用的config檔通常也不會拿來通用,default直接綁死在class內就好。

class ConfigSettings:
    def __init__(self, lang):
        self.lang = lang if lang is not None else "zh-TW"
        
class Config:
    def __init__(self, settings:ConfigSettings):
        self.setting = settings

其實default直接寫在Config裡面就好。ConfigSettings那根本是不必要的拆分,除非有特殊設計。

你原本那樣寫根本無視了作用域,就算作用域讓你可以進行這樣的操作,也還有無限繼承樹的問題。

我大致知道了
本來我的想法是

class Config:
    class default:
        class language:
            #code
        class page2:
            #code
    class first_oneline:
        class language(default.language):
            #code
        class page2(default.page2):
            #code
    class ......:
        class ......(default. ......)
        class ......(default. ......)

其實default直接寫在Config裡面就好。
我理解到的意思是

class Config:
    class default:
        #code
    class first_oneline(default):
        #code

雖然不知道對不對
但如果我是這樣寫我代碼可能就要變成底下兩種

class Config:
    class default:
        class language:
            #code
        class page2:
            #code
        class page3:
            #code
            
  # 這裡是first_oneline
    class language(default.language):
        #code
    class page2(default.page2):
        #code
    class page3(default.page3):
        #code
  # 這裡是(其他分類)
    class ......(default. ......)
    class ......(default. ......)
class Config:
    class default:
        class language:
            #code
        class page2:
            #code
        class page3:
            #code
            
    if '這裡是first_oneline' != 0:
        class language(default.language):
            #code
        class page2(default.page2):
            #code
        class page3(default.page3):
            #code
    if '這裡是(其他分類)' != 0:
        class ......(default. ......)
        class ......(default. ......)

好吧,也不是不行,就這樣做好了XD
這樣好像也可以XDDD


那不過我還有一個問題一直想不明白

class B1:
    def __init__(self,setting=None):
        self.setting=setting if setting is not None else 'No setting'
class B2:
    class C:
        def __init__(self, B1=B1):
            self.reset=B1().setting

print(B2.C().reset)
#-------------------------------------------------
No setting
#-------------------------------------------------

上面的狀況是分開放
這種狀況是可以繼承的

但是下面這樣,把兩個放一起就不行了?

class A:
    class B1:
        def __init__(self,setting=None):
            self.setting=setting if setting is not None else 'No setting'
    class B2:
        class C:
            def __init__(self, B1=A.B1):
                self.reset=B1().setting

print(A.B2.C().reset)
#-------------------------------------------------
A未定義
#-------------------------------------------------
class A:
    class B1:
        def __init__(self,setting=None):
            self.setting=setting if setting is not None else 'No setting'
    class B2:
        class C:
            def __init__(self, B1=B1):
                self.reset=B1().setting

print(A.B2.C().reset)
#-------------------------------------------------
B1未定義
#-------------------------------------------------

在我的觀念中
C應該是要繼承B1
也確實不在同一個class裡時 是這樣的沒錯
但是當我把全部放在A中時
C卻沒辦法繼承A底下的B1

雖然你說這樣會有無限繼承樹的問題
可是我不太懂
如果我今天是直接C繼承A
那確實會變成
C繼承A
以及A底下的B1、B2以及C與C繼承的A
以及A底下的B1、B2以及C與C繼承的A
以及A底下的B1、B2以及C與C繼承的A......

到這裡為止我理解(或是我有誤解XDD)
那為甚麼不能C繼承A的B1
難道他是C同時繼承A以及B1嗎?
但我在class外用A.B1繼承的時候
沒辦法呼叫A底下的其他東西呀?

這是有甚麼原因嗎?
我是在哪一個地方有誤解的?
真的沒有任何方法可以讓C繼承B1嗎?

froce iT邦大師 1 級 ‧ 2024-08-02 10:51:02 檢舉

...
class是類別,你把它當實例用。

  1. class是設計藍圖,實例是依照設計藍圖和init時輸入的參數,產生的物體。
  2. 所以default基本上也是一個Config,class一定和你後來要自訂的設定是一樣的,你根本不需要多為default設一個class。
  3. 你這個就只需要一層去設計就夠了,要簡潔就像我ConfigSetting那樣寫就行了。
  4. 繼承不是class in class,沒人規定class in class一定是繼承關係,另外依照作用域這繼承關係根本不可能也不可以成立。class in class通常是為了我外層class內部的資料不希望給人直接操作時候才用。所以我前面才說「在class裡面寫class通常是為了封裝,不是為了繼承。」
  5. 另外補充一點,通常Config這種東西更需要類型檢查,而不是繼承,去看typingdataclass

好的,我知道了
讓我消化一下XD

反正最簡單就是
沒任何方法可以放default.lang在first.lang()的括號中對吧?

froce iT邦大師 1 級 ‧ 2024-08-02 11:51:25 檢舉

...
你類別的用法錯的一踏糊塗,建議重新看看到底該怎麼用。
另外建議重開一篇,去敘述你需要的,直接寫給你看會比較好,而不是用你錯誤的理解去繞...

然後建議多去看看github,去看看別人的專案原始碼是怎麼寫的。
https://github.com/line/line-bot-sdk-python
我個人建議line-bot可以好好看一看,不大

好的我知道了
我會去看的

順一說
我差不多只是把class拿來當分類分組的東西XD
因為本來一開始是以為class是組別的意思
像是一個大團體可以分成好多小團

現在知道不完全是了XD

froce iT邦大師 1 級 ‧ 2024-08-02 12:58:16 檢舉

你把class當成藍圖就行了,譬如你是個ODM,自己生產吹風機,也要幫A、B牌設計並生產吹風機。

# 設計階段(類別)
class Dryer:
    def __init__(self):
        self.input_volt = 110
        self.watt = 1500

# A牌有負離子功能
class A_Dryer(Dryer):
    def __init__(self):
        super().__init__()
        self.ions = True

# B牌電壓220
class B_Dryer(Dryer):
    def __init__(self):
        super().__init__()
        self.input_volt = 220
        
# 生產階段(實例)
m = Dryer()
a = A_Dryer()
print(a.ions)
b = B_Dryer()
print(b.input_volt)

子項在實例化時會用super()去得到母項,然後去調用魔術方法 init()
去生成母項 init() 裡的所有項目,後面再擴充(A牌)或是覆蓋(B牌)的屬性
繼承是這樣用的,不是像你那樣亂來...

原來是這樣!

我本來試想的是如果可以就把上面三個class用大class包起來
現在我懂你的意思了!!
藍圖還沒完稿就想使用當然是不行
如果硬要使用就只能在畫一個小藍圖在旁邊
完全懂了!!!

看來包起來要用if (被打W

if '這裡是吹風機' != 0:
    class......
    class......
# 因為這樣在軟體中才可以摺起來,太多行找不到XD
# 也就是說 if 是用來佔位子的XD
froce iT邦大師 1 級 ‧ 2024-08-02 14:07:49 檢舉

ㄜ...我覺得你還是沒懂。需求寫出來寫清楚,別人寫給你看比較好。
基本上我覺得依你目前說的來看,就是需要dataclass而已。
dataclass可以直接指定預設值,可以驗證資料類型,甚至可以驗證資料是不是符合定義,譬如一定是正數,在5~100之間

需求寫出來寫清楚

我只是想要摺起來XD
摺在一行裡W
最一開始那樣問是因為不想用if做廢行
if的方法我已經會了,我想學別的我不會的
所以if 'XXXXXX' != 0:單純只是為了做標籤

本來:
https://ithelp.ithome.com.tw/upload/images/20240802/20145811dVeTaook7Y.png
後來:
https://ithelp.ithome.com.tw/upload/images/20240802/20145811EhQywVnYfH.png


阿對,既然都提到了,可以解釋一下dataclass嗎?
我查到的好像是類似
定義:資料類型
比如:
class XXX:
coint:int

這種的話我可能用不了?
就以Lang就好
我的class Default.language底下就已經有很多看起來沒辦法的了

Pass = #True or False
if Pass:
    pass
else:#這裡是最外層了再往外是判斷是否跳過所有
    if 'class Default' == 0:
        class Default
            class Buttons:#跳過
            class language(View,Select):
                def __init__(self):
                    super().__init__()
                    variable={}
                    exec(open_file,globals(),variable)
                    lang = variable.get('lang')
                    options=[]
                    for language in os.listdir('cmds/rpg_define'):
                        if language.endswith('lang'):
                            with open(f'cmds/rpg_define/{language}','r',encoding='utf-8') as Lang_file:
                                for line in Lang_file:
                                    if line.strip().startswith('language-Type'):
                                        line = line.strip().split('=',1)[1]
                                        options.append(SelectOption(label=line,value=language[:-5]))
                    options = Select(placeholder=f'{eval(lang.get('language','"rerror402"'))}...',options=options)
                    options.callback = self.options_callback
                    self.add_item(options)
                    decided = Default.Buttons.decided()
                    decided.callback = self.decided_callback
                    self.add_item(decided)
                    back = Default.Buttons.back()
                    back.callback = self.back_callback
                    self.add_item(back)
        #下面還有但跳過,只有範例
                async def back_callback(self, interaction: discord.Interaction):
                    await interaction.response.edit_message(content=None,embed=embed,view=Interface_Config.first_online.Player_Guidelines())
            
        #上面還有但跳過,只有範例
            class Race(View,Select):
                    def __init__(self):
                        super().__init__()
                        pass#還沒寫
    #class Default只到這
    
    if 'class Interface_Config' == 0:
        class Interface_Config:
            class first_online:
                class language(Default.language):
                    pass#我真的只打pass
                class Race(Default.Race):#預計,還沒寫
                    pass#我真的只打pass
            class setting:
                class language(Default.language):
                    pass#我真的只打pass
                class Race(Default.Race):#預計,還沒寫
                    pass#我真的只打pass
    #class Interface_Config只到這

感覺你一直想讓我丟出來
比較好判斷我到底要做甚麼XD
不過就是不想丟這個
因為會自動換行,我怕我每次回來看都要花時間找XD

froce iT邦大師 1 級 ‧ 2024-08-03 23:08:56 檢舉

我只能說你這根本就是亂寫...沒人這樣用class的。
前面就說過了,class是藍圖,沒人有辦法對藍圖進行操作。
要進行操作的會是實例。

我要發表回答

立即登入回答