Ördek yazma nedir?


429

Çevrimiçi yazılımda rastgele konular okurken ördek yazarak geçtim ve tam olarak anlamadım.

“Ördek yazma” nedir?


1
@Mitch denedim ve bir çeşit miras olarak bir şey aldım. Ama fazla takip edemedim. Yanlış soruyu sorduğumda üzgünüm.
sushil bharwani

3
@sushil bharwani: hayır, kızgın değil. Ancak insanlar ilk çağrı limanı olarak (yani yaptığınız ilk şey) buraya göndermeden önce aramayı denemeyi beklerler.
Mitch Wheat

104
Yukarıdaki argümanlar göz önüne alındığında, yığın akması gerçekten gerekli görünmüyor çünkü birisinin aklınıza gelebilecek hemen hemen her sorunun internette bir yerde cevaplandığından eminim ve eğer değilse cevap daha kolay ve eleştirisiz bir şekilde e-posta ile elde edilebilir. bilgili arkadaş. Sanırım çoğunuz yığın akışı noktasını kaçırdınız.
rhody

41
Eminim SO'nun "kanonik soruların deposu" olması amaçlanmış bir yerde okudum ve bundan daha kanonik olamayacağınızdan eminim.
heltonbiker

Yanıtlar:


302

Güçlü yazımları olmayan dinamik dillerde kullanılan bir terimdir .

Fikir, bir nesne üzerinde var olan bir yöntemi çağırmak için bir türe ihtiyacınız olmamasıdır - üzerinde bir yöntem tanımlanmışsa, onu çağırabilirsiniz.

Adı "Ördek gibi görünüyor ve ördek gibi quacks, o bir ördek" ifadesinden geliyor.

Wikipedia çok daha fazla bilgiye sahip.


25
Güçlü Yazma kullanmaya dikkat edin. O kadar iyi tanımlanmış değil. Ördek Yazma da değil. Google Go veya Ocaml, yapısal bir alt tip oluşturma özelliğine sahip, statik olarak yazılmış dillerdir. Bu ördek türü diller mi?
CRAP CEVAPLARI

7
Ördek yazmak için daha iyi bir cümle: "Öyle bir ördek olduğunu söylüyorsa .. bu benim için yeterli. bkz. pyvideo.org/video/1669/keynote-3 28:30 veya youtube.com/watch?v=NfngrdLv9ZQ#t=1716
tovmeod

7
Ördek yazmanın sadece dinamik dillerde kullanılması gerekmez. Objective-C dinamik bir dil değildir ve ördek yazmayı kullanır.
eyuelt

12
Hem Python hem de Ruby güçlü yazılan dillerdir ve her ikisi de Ördek Yazma özelliğine sahiptir. String Typing, Duck Typing'e sahip olmadığı anlamına gelmez.
alanjds

8
Bunu küçümsüyorum. Ördek ördeğinin tipin gücü ile ilgisi yoktur, sadece bir arabirime sahip olsun ya da olmasın, bir yönteme sahip herhangi bir nesneyi kullanabilme yeteneği.
e-satis

209

Ördek yazımı , bir işlemin , işlenenlerinin yerine getirmesi gereken gereksinimleri resmi olarak belirtmediği , ancak verilenle denediği anlamına gelir .

Diğerlerinin söylediklerinden farklı olarak, bunun dinamik diller veya miras sorunları ile ilgili olması gerekmez.

Örnek görev:Quack Bir nesne üzerindeki bazı yöntemleri çağırın .

Olmadan ördek-yazma kullanılırken, bir işlev fbu görevi yapıyor onun argümanı bazı yöntem desteklemek zorunda olduğu önceden belirtmek zorundadır Quack. Ortak bir yol, arayüzlerin kullanılmasıdır

interface IQuack { 
    void Quack();
}

void f(IQuack x) { 
    x.Quack(); 
}

Arama f(42)başarısız oluyor, ancak bir -subtype örneği f(donald)olduğu sürece çalışıyor .donaldIQuack

Başka bir yaklaşım yapısal yazımdır - ancak yine de yöntem Quack(), quackönceden derleyici hatasına neden olacağını kanıtlayamayan herhangi bir şey resmi olarak belirtilir .

def f(x : { def Quack() : Unit }) = x.Quack() 

Hatta yazabiliriz

f :: Quackable a => a -> IO ()
f = quack

Haskell'de, Quackabletip sınıfının yöntemimizin varlığını sağlaması.


Ördek yazması bunu nasıl değiştirir?

Dediğim gibi, bir ördek yazım sistemi gereksinimleri belirtmiyor, sadece bir şey işe yarıyorsa çalışır .

Böylece, Python'lar gibi dinamik bir tip sistem her zaman ördek yazmayı kullanır:

def f(x):
    x.Quack()

Bir destekleyici falırsa , her şey yolunda, eğer değilse, çalışma zamanında çökecektir.xQuack()

Ancak ördekle yazma, dinamik yazma anlamına gelmez - aslında, herhangi bir gereksinim vermeyen çok popüler ama tamamen statik bir ördek yazma yaklaşımı da vardır:

template <typename T>
void f(T x) { x.Quack(); } 

Fonksiyon bazı istediği herhangi bir şekilde söylemez xo kutuyu Quackbunun yerine sadece çalışır, derleme sırasında 's ince ve her şey çalışıp çalışmadığını.


5
Bunu mu demek istediniz: void f (IQuak x) {x.Quak (); } (K.Quack yerine) çünkü işlev f parametresi IQuack x değil Iquack k değil, çok küçük bir hata ama düzeltilmesi gerekiyor gibi hissettim :)
dominicbri7

Wikipedia'ya göre, son örneğiniz "ördek tipi yazma" değil, "yapısal tipleme" dir.
Brilliand

Görünüşe göre bu tartışma için ayrı bir soru var: stackoverflow.com/questions/1948069/…
Brilliand

1
Öyleyse ne dediğini anlarsam, ördek yazmayı destekleyen bir dil ile olmayan bir dil arasındaki fark sadece ördek yazmayla olan bir şeydir, bir işlevin kabul ettiği nesnelerin türünü belirtmeniz gerekmez mi? def f(x)yerine def f(IQuack x).
PProteus

124

Basit Açıklama (kodsuz)

Sorunun anlambiliminin tartışılması oldukça nüanslıdır (ve çok akademiktir), ancak genel fikir şudur:

Ördek Yazma

(“Ördek gibi yürür ve ördek gibi quacks yaparsa o zaman bir ördek.”) - EVET! ama bu ne anlama geliyor ??! Bu en iyi örnek olarak gösterilmiştir:

Ördek Yazma işlevselliğine örnekler:

Sihirli bir asam olduğunu hayal et. Özel güçleri var. Asayı sallayıp "Sür!" o zaman, araba sürüyor!

Başka şeyler üzerinde çalışıyor mu? Emin değilim: bir kamyonda deniyorum. Vay canına - o da sürüyor! Sonra uçaklar, trenler ve 1 Woods üzerinde denemek (onlar 'golf topu' sürücü 'için kullandıkları golf kulübü türüdür). Hepsi sürüyor!

Ama bir çay fincanı muydu? Hata: KAAAA-BOOOOOOM! o kadar iyi sonuç vermedi. ====> Çay bardakları araba kullanamaz !! yaa !?

Temelde ördek yazma kavramı budur. Satın almadan önce bir dene sistemi. Çalışırsa, her şey yolunda. Ama eğer başarısız olursa, hala elindeki bir el bombası gibi, yüzüne patlayacak.

Diğer bir deyişle, biz nesne ne ilgilendiğiniz yapabilirsiniz diğerlerinden ziyade nesnenin ne .

Örnek: statik olarak yazılan diller

Biz ilgilenen olsaydı nesne aslında ne , o zaman bizim sihir sadece önceden seti, yetkili türleri üzerinde çalışacak - bu durumda otomobillere değil sürebilirsin diğer nesneler üzerinde başarısız olur : kamyon, motosiklet, tuk tuks vs. Kamyonlarda çalışmaz çünkü sihirli değnekimiz sadece arabalarda çalışmasını bekler .

Başka bir deyişle, bu senaryoda, sihirli değnek , nesnenin yapabileceği şeyden (örneğin, arabalar, kamyonlar vb. Gidip gelemeyeceği) nesnenin ne olduğuna (bir araba mı?) Çok yakından bakar .

Bir şekilde büyü alabilirsiniz asa kamyonlar hem beklemek eğer sürücüye bir kamyon almak tek yolu ve ( "ortak bir arabirim uygulama" ile belki) arabalar. Bunun ne anlama geldiğini bilmiyorsanız, o an için onu görmezden gelin.

Özet: Anahtar çıkarma

Ne ördek yazarak içinde önemli olan nesne aslında ne yapmak yerine nesne olandan ise .


Davranış hakkında daha fazla önem vermenizin önermesini ilginç buluyorum, bu tanım. Şüphesiz BDD yakut gibi dillerde çok başarılı.
Pablo Olmos de Aguilera

27

Bir nesneyi alan Birdve walk()yöntemini çağıran basit bir işlev tasarladığınızı düşünün . Düşünebileceğiniz iki yaklaşım vardır:

  1. Bu benim fonksiyonum ve sadece kabul ettiğinden emin olmalıyım Bird, yoksa kodları derlenmeyecektir. Herkes benim işlevi kullanmak istiyorsa, o sadece kabul farkında olmalıdır Birds
  2. Benim fonksiyonum herhangi olsun objectsve ben sadece nesnenin walk()yöntemini çağırıyorum . Yani, eğer objectkutu walk()doğruysa, yapamazsa fonksiyonum başarısız olur. Yani burada nesnenin bir Birdşey ya da başka bir şey olması önemli değil, yapabilmesi önemlidir walk() (Bu ördek yazmasıdır )

Göz önüne alınmalıdır ördek yazarak örnek Python kullanımlar için, bazı durumlarda yararlı olabilir yazarak ördek çok.


Yararlı okuma


1
Güzel açıklama, herhangi bir avantajı nelerdir?
sushil bharwani

2
Bu cevap basit, açık ve muhtemelen yeni başlayanlar için en iyisidir. Bu cevabı yukarıdaki cevapla birlikte okuyun (ya da hareket ederse, arabalar ve çay
bardaklarından bahseden

18

Wikipedia'nın oldukça ayrıntılı bir açıklaması var:

http://en.wikipedia.org/wiki/Duck_typing

ördek yazma, bir nesnenin geçerli yöntem ve özellik kümesinin, belirli bir sınıftan miras alınması veya belirli bir arabirimin uygulanmasından ziyade geçerli semantiği belirlediği bir dinamik yazma tarzıdır.

Önemli not, ördek yazarken bir geliştiricinin, nesnenin asıl altta yatan türden ziyade tüketilen parçaları ile daha fazla ilgilenmesi muhtemeldir.


13

Eski deyimi tekrarlayan birçok cevap görüyorum:

Ördek gibi görünüyor ve ördek gibi quacks, bu bir ördek

ve sonra ördek yazarak neler yapabileceğinizin açıklamasına veya konsepti daha da gizleyen bir örneğe dalın.

Çok fazla yardım bulamıyorum.

Bu bulduğum ördek yazmayla ilgili düz bir İngilizce cevap en iyi girişimdir:

Ördek Yazma, bir nesnenin ne olduğu ile değil, ne yapabileceği ile tanımlandığı anlamına gelir.

Bu, bir nesnenin sınıfı / türü ile daha az ve onun üzerinde hangi yöntemlerin çağrılabileceği ve üzerinde hangi işlemlerin gerçekleştirilebileceğiyle daha fazla ilgili olduğumuz anlamına gelir. Türünü önemsemiyoruz, ne yapabileceğini önemsiyoruz .


3

Ördek yazarak:

Ördek gibi konuşuyor ve yürüyorsa, o zaman bir ördek

Bu genellikle denir kaçırma ( dışaçekimsel muhakeme ya da adlandırılan retroduction sanırım daha net tanım):

  • dan C (Sonuç, gördüğümüz ) ve R (kural, ne biliyoruz ), biz karar kabul / / varsayalım P (Önerme, mülkiyet başka bir deyişle belirli bir gerçeği)

    ... tıbbi teşhisin temeli

    ördekler ile: C = yürüyüşler, görüşmeler , R = ördek gibi , P = ördek

Programlamaya geri dön:

  • Nesne O yöntemi / özellik vardır MP1 ve arayüz / tip T gerektirir / tanımlar MP1

  • Nesne O yöntemi / özellik vardır MP2 ve arayüz / tip T gerektirir / tanımlar MP2

  • ...

Yani, daha basit kabul etmektense MP1 sürece bazı tanımını karşılayan olduğu gibi herhangi bir nesne üzerinde ... MP1 iddiası ile ..., derleyici / çalışma zamanı da tamam olmalıdır o tip taşımaktadır T

Ve yukarıdaki örneklerde durum böyle mi? Ördek yazmak aslında hiç yazmak değil midir? Yoksa örtük yazma mı demeliyiz?


3

Dilin kendisine bakmak yardımcı olabilir; genellikle bana yardımcı olur (ben anadili İngilizce değilim).

İçinde duck typing:

1) kelime typingklavyede yazmak anlamına gelmez (aklımdaki kalıcı görüntü gibi), " bu şey ne tür bir şey? "

2) duckbu tespitin nasıl yapıldığını ifade eder; "gevşek" bir belirleyici. " Ördek gibi yürüyorsa ... o zaman bir ördek ". 'Gevşek' çünkü şey bir ördek olabilir ya da olmayabilir, ama aslında bir ördek olup olmadığı önemli değil; önemli olan ördeklerle yapabileceğim ve ördeklerin sergilediği davranışları beklediğim. Ekmek kırıntılarını besleyebilirim ve şey bana doğru gidebilir veya bana şarj edebilir ya da geri çekilebilir ... ama beni bir grizzly gibi yiyip bitmeyecek.


2

Genel cevap vermediğimi biliyorum. Ruby'de, değişken veya yöntem türlerini beyan etmiyoruz - her şey sadece bir tür nesne. Kural "Sınıflar Tür Değildir"

Ruby'de sınıf asla (Tamam, neredeyse hiç) tür değildir. Bunun yerine, bir nesnenin türü, o nesnenin yapabilecekleriyle daha fazla tanımlanır. Ruby'de, bu ördek yazmaya diyoruz. Bir nesne ördek gibi yürür ve ördek gibi konuşursa, tercüman ona ördekmiş gibi davranmaktan mutluluk duyar.

Örneğin, bir dizeye şarkı bilgisi eklemek için bir rutin yazıyor olabilirsiniz. Bir C # veya Java arka planından geliyorsanız, bunu yazmaya cazip gelebilirsiniz:

def append_song(result, song)
    # test we're given the right parameters 
    unless result.kind_of?(String)
        fail TypeError.new("String expected") end
    unless song.kind_of?(Song)
        fail TypeError.new("Song expected")
end

result << song.title << " (" << song.artist << ")" end
result = ""

append_song(result, song) # => "I Got Rhythm (Gene Kelly)"

Ruby'nin ördek yazmasını kucaklayın ve çok daha basit bir şey yazın:

def append_song(result, song)
    result << song.title << " (" << song.artist << ")"
end

result = ""
append_song(result, song) # => "I Got Rhythm (Gene Kelly)"

Bağımsız değişkenlerin türünü kontrol etmenize gerek yoktur. << (sonuç durumunda) veya başlık ve sanatçıyı (şarkı durumunda) destekliyorlarsa, her şey işe yarayacaktır. Yapmazlarsa, yönteminiz yine de bir istisna atar (tıpkı türleri kontrol ederseniz yapmış olacağı gibi). Ancak kontrol olmadan, yönteminiz aniden çok daha esnektir. << kullanarak eklenen bir dizi, dize, dosya veya başka bir nesneyi iletebilirsiniz ve bu sadece işe yarayacaktır.


2

Ördek Yazma Tipi İpucu değil!

Temel olarak "ördek yazmayı" kullanmak için, ortak bir arabirim kullanarak belirli bir türü değil, daha geniş bir alt türü (kalıtımdan bahsetmiyorum, alt türlerden bahsettiğimde aynı profillere uyan "şeyleri kastediyorum) hedefleyeceksiniz. .

Bilgi depolayan bir sistem hayal edebilirsiniz. Bilgi yazmak / okumak için bir çeşit depolama alanına ve bilgiye ihtiyacınız vardır.

Depolama türleri şunlar olabilir: dosya, veritabanı, oturum vb.

Arabirim, depolama türünden bağımsız olarak kullanılabilir seçenekleri (yöntemleri) size bildirir, yani bu noktada hiçbir şey uygulanmaz! Başka bir deyişle, Arayüz bilginin nasıl saklanacağı hakkında hiçbir şey bilmiyor.

Her depolama sistemi, aynı yöntemleri uygulayarak arabirimin varlığını bilmelidir.

interface StorageInterface
{
   public function write(string $key, array $value): bool;
   public function read(string $key): array;
}


class File implements StorageInterface
{
    public function read(string $key): array {
        //reading from a file
    }

    public function write(string $key, array $value): bool {
         //writing in a file implementation
    }
}


class Session implements StorageInterface
{
    public function read(string $key): array {
        //reading from a session
    }

    public function write(string $key, array $value): bool {
         //writing in a session implementation
    }
}


class Storage implements StorageInterface
{
    private $_storage = null;

    function __construct(StorageInterface $storage) {
        $this->_storage = $storage;
    }

    public function read(string $key): array {
        return $this->_storage->read($key);
    }

    public function write(string $key, array $value): bool {
        return ($this->_storage->write($key, $value)) ? true : false;
    }
}

Şimdi, her bilgi yazmanız / okumanız gerektiğinde:

$file = new Storage(new File());
$file->write('filename', ['information'] );
echo $file->read('filename');

$session = new Storage(new Session());
$session->write('filename', ['information'] );
echo $session->read('filename');

Bu örnekte Depolama yapıcısında Ördek Yazma özelliğini kullanacaksınız:

function __construct(StorageInterface $storage) ...

Umarım yardımcı olmuştur;)


2

Ördek yazarak tekniği ile Ağaç Geçişi

def traverse(t):
    try:
        t.label()
    except AttributeError:
        print(t, end=" ")
    else:
        # Now we know that t.node is defined
        print('(', t.label(), end=" ")
        for child in t:
            traverse(child)
        print(')', end=" ")

0

Dinamik yazım, statik yazım ve ördek yazmayı karıştırmanın karışık olduğunu düşünüyorum. Ördek yazımı bağımsız bir kavramdır ve Go gibi statik olarak yazılan bir dil, ördek yazmayı uygulayan bir tür kontrol sistemine sahip olabilir. Bir tür sistemi, (bildirilen) bir nesnenin yöntemlerini kontrol eder, ancak türü değil, buna ördek yazma dili denebilir.


-1

Ünlü cümleyi kendi yolumda anlamaya çalışıyorum: "Bir nesnenin umrunda olmayan Python dozu gerçek bir ördek mi, değil mi. Tek umurunda olan şey, ilk 'quack', ikinci 'ördek gibi'.

İyi bir web sitesi var. http://www.voidspace.org.uk/python/articles/duck_typing.shtml#id14

Yazar, ördek yazmanın kendi iç veri yapısına sahip olan ancak normal Python sözdizimi kullanılarak erişilen kendi sınıflarınızı oluşturmanıza izin verdiğini belirtti.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.